using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using ZoomEngine.Animation;

namespace tutFuelCellGame
{

    public class FuelCell : GameObject
    {
        private readonly ClockManager clockManager;
        private readonly SoundManager soundManager;

        protected enum FuelCellState
        {
            Active, Found, Hidden
        }

        protected FuelCellState State { get; set; }

        public float RotationY { get; set; }

        public bool Retrieved
        {
            get { return State != FuelCellState.Active; }
        }

        public void Found()
        {
            if (State == FuelCellState.Active)
            {
                State = FuelCellState.Found;
                StartFoundAnimation();
                soundManager.OnFuelCellFound();
            }
        }

        private void StartFoundAnimation()
        {
            var shrink = new FloatFromToAnimation(clockManager)
            {
                From = Scale,
                To = Scale * .2f,
                ProgressTransform = ProgressTransforms.Bounce,
                Apply = (x) => { Scale = x; }
            };
            shrink.Complete += (s, e) => Hide();
            shrink.Start();
        }


        private void Hide()
        {
            State = FuelCellState.Hidden;
        }


        public FuelCell(ClockManager clockManager, SoundManager soundManager)
            : base()
        {
            State = FuelCellState.Active;
            this.clockManager = clockManager;
            this.soundManager = soundManager;
        }

        public void Reset()
        {
            Scale = 1f;
            State = FuelCellState.Active;
        }

        public void LoadContent(ContentManager content, string modelName)
        {
            Model = content.Load<Model>(modelName);
            Position = Vector3.Up;

            BoundingSphere = CalculateBoundingSphere(GameConstants.FuelCellBoundingSphereFactor);

            var upDownBobbing = new FloatFromToAnimation(clockManager)
            {
                From = BoundingSphere.Radius * 1.5f,
                To = BoundingSphere.Radius * 2.5f,
                Duration = 1f,
                AutoReverse = true,
                RepeatCount = int.MaxValue,
                BeginOffset = 1f,
                Apply = (v) => { Vector3 p = Position; p.Y = v; Position = p; }
            };

            upDownBobbing.Start();
            var rotation = new FloatFromToAnimation(clockManager)
            {
                From = 0,
                To = +MathHelper.TwoPi,
                Duration = 2f,
                AutoReverse = false,
                RepeatCount = int.MaxValue,
                Apply = (v) => { RotationY = v; }
            };
            rotation.Start();
        }

        public void Draw(Matrix view, Matrix projection)
        {
            if (State != FuelCellState.Hidden)
            {
                Matrix worldMatrix = GetWorldMatrix();
                DrawModelMeshes(worldMatrix, view, projection);
            }
        }

        public void DrawShadow(Matrix view, Matrix projection, Matrix shadow)
        {
            if (State != FuelCellState.Hidden)
            {
                Matrix worldMatrix = GetWorldMatrix();
                DrawModelMeshesWithShadow(worldMatrix, view, projection, shadow);
            }
        }

        private Matrix GetWorldMatrix()
        {
            Matrix scale = Matrix.CreateScale(Scale);
            Matrix translateMatrix = Matrix.CreateTranslation(Position);
            Matrix rotations = Matrix.CreateRotationY(RotationY);

            return scale * rotations * translateMatrix;
        }


        public void Update(BoundingSphere fuelCarrierBounds)
        {
            switch (State)
            {
                case FuelCellState.Active:
                    if (BoundingSphere.Intersects(fuelCarrierBounds))
                        Found();
                    break;
                case FuelCellState.Found:
                    Position = fuelCarrierBounds.Center + (Vector3.Up * 0.5f);
                    break;
                case FuelCellState.Hidden:
                    break;
            }

        }

    }
}